#!/usr/bin/env ruby

require 'thread'
require 'net/smtp'

require 'simmon/logging'

module Simmon
  # A notifier is an actor which sits and listens for incoming events
  # on a mailbox, and sends notifications of those events to some
  # destination. Individual subclasses implement different forms of
  # delivery.
  class Notifier
    # Initialize a notifier of events delivered to the given mailbox.
    def initialize(mailbox)
      @mailbox = mailbox

      @log = Log4r::Logger['simmon']
      
      Thread.new() { notify_loop() }
    end

    def notify_loop()
      @log.debug("#{self.class()} up and running for mailbox #{@mailbox.name()}")
      begin
        while true
          event = @mailbox.get()
          
          begin
            notify(event)
          rescue
            @log.warn("#{self.class()}: event notification for mailbox #{@mailbox.name()} failed: #{$1} #{$!.backtrace()}")
          end
        end
      rescue
        @log.fatal("#{self.class()} for mailbox #{@mailbox.name()} exiting: #{$1} #{$!.backtrace()}")
      end
    end

    # Actually perform notification for an event. This method must be
    # implemented by subclasses.
    def notify(event)
      raise NotImplementedError("#{self.class.name}#notify() is not implemented")
    end
  end
  
  # Sends notifications by E-Mail, via the SMTP protocol
  class SmtpNotifier < Notifier
    # from: from address to use
    # destinations: array of destination e-mail addresses
    def initialize(mailbox, from, destinations, smtp_host = "localhost", smtp_port = 25)
      super(mailbox)

      @from = from
      @destinations = destinations
      @host = smtp_host
      @port = smtp_port

      # prepare cached versions of static headers
      destlist = ""
      @destinations.each() { |d| destlist = "#{destlist},#{d}" }
      destlist = destlist[1..destlist.size()]
      @static_headers = "From: #{@from}\r\nTo: #{destlist}\r\n"
    end

    def notify(event)
      sensor = event[0]
      state = event[1]

      if state.ok() then
        state_summary = "UP"
      else
        state_summary = "DOWN"
      end

      # todo, we should properly encode the subject and body
      subject = "#{sensor.name()}: #{state_summary}"
      body = "#{state}"

      msg = "#{@static_headers}Subject: #{subject}\r\n\r\n#{body}"

      Net::SMTP.start(@host, @port) do |smtp|
        smtp.send_message(msg, @from, @destinations)
      end
    end
  end
end

